package com.elbis.business.entity;

import static javax.persistence.GenerationType.IDENTITY;

import java.io.Serializable;
import java.sql.Date;
import java.util.ArrayList;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Past;
import javax.validation.constraints.Size;

import com.elbis.business.entity.authentication.Authentication;
import com.elbis.business.entity.locale.City;
import com.elbis.business.entity.locale.Country;
import com.elbis.business.entity.locale.Language;

@Entity
@Table(name = DataBaseConstants.TABLE_GAMER, catalog = DataBaseConstants.CATALOG, uniqueConstraints = @UniqueConstraint(columnNames = { DataBaseConstants.COLUMN_EMAIL }))
public class Gamer implements Serializable {

	private static final long serialVersionUID = 6230715844518776003L;

	private Long id;

	@Size(max = 60)
	@NotNull
	private String email;

	@NotNull
	@Size(max = 25)
	private String password;

	@Size(max = 45)
	private String name;

	@Size(max = 45)
	private String surname;

	@Size(max = 45)
	private String nationality = null;

	@Column(name = "dateofbirth")
	@Past
	private Date dateOfBirth = null;

	private Country country = null;

	private City city = null;

	private Language language = null;

	@Column(nullable = false, columnDefinition = "TINYINT(1)")
	private boolean active;

	private List<Game> games = null;

	private List<Gamer> friends = null;

	private List<Authentication> authentications = null;

	@Id
	@GeneratedValue(strategy = IDENTITY)
	@Column(name = DataBaseConstants.COLUMN_ID, nullable = false)
	/**
	 * @return the id
	 */
	public Long getId() {
		return id;
	}

	/**
	 * @param id
	 *            the id to set
	 */
	public void setId(Long id) {
		this.id = id;
	}

	@Column(name = DataBaseConstants.COLUMN_EMAIL, unique = true, nullable = false, length = 60)
	/**
	 * @return the email
	 */
	public String getEmail() {
		return email;
	}

	/**
	 * @param email
	 *            the email to set
	 */
	public void setEmail(String email) {
		this.email = email;
	}

	@Column(name = DataBaseConstants.COLUMN_PASSWORD, nullable = false, length = 25)
	/**
	 * @return the password
	 */
	public String getPassword() {
		return password;
	}

	/**
	 * @param password
	 *            the password to set
	 */
	public void setPassword(String password) {
		this.password = password;
	}

	@Column(name = DataBaseConstants.COLUMN_NAME, nullable = true, length = 45)
	/**
	 * @return the name
	 */
	public String getName() {
		return name;
	}

	/**
	 * @param name
	 *            the name to set
	 */
	public void setName(String name) {
		this.name = name;
	}

	@Column(name = DataBaseConstants.COLUMN_SURNAME, nullable = true, length = 45)
	/**
	 * @return the surname
	 */
	public String getSurname() {
		return surname;
	}

	/**
	 * @param surname
	 *            the surname to set
	 */
	public void setSurname(String surname) {
		this.surname = surname;
	}

	@Column(name = "active", nullable = false)
	/**
	 * @return the active
	 */
	public boolean isActive() {
		return active;
	}

	/**
	 * @param active
	 *            the active to set
	 */
	public void setActive(boolean active) {
		this.active = active;
	}

	/**
	 * @return the nationality
	 */
	public String getNationality() {
		return nationality;
	}

	/**
	 * @param nationality
	 *            the nationality to set
	 */
	public void setNationality(String nationality) {
		this.nationality = nationality;
	}

	/**
	 * @return the dateOfBirth
	 */
	public Date getDateOfBirth() {
		return dateOfBirth;
	}

	/**
	 * @param dateOfBirth
	 *            the dateOfBirth to set
	 */
	public void setDateOfBirth(Date dateOfBirth) {
		this.dateOfBirth = dateOfBirth;
	}

	@OneToOne
	@JoinColumn(name = "country_id")
	/**
	 * @return the country
	 */
	public Country getCountry() {
		return country;
	}

	/**
	 * @param country
	 *            the country to set
	 */
	public void setCountry(Country country) {
		this.country = country;
	}

	@OneToOne
	@JoinColumn(name = "city_id")
	/**
	 * @return the city
	 */
	public City getCity() {
		return city;
	}

	/**
	 * @param city
	 *            the city to set
	 */
	public void setCity(City city) {
		this.city = city;
	}

	@OneToOne
	@JoinColumn(name = "language_id")
	/**
	 * @return the language
	 */
	public Language getLanguage() {
		return language;
	}

	/**
	 * @param language
	 *            the language to set
	 */
	public void setLanguage(Language language) {
		this.language = language;
	}

	@ManyToMany(fetch = FetchType.EAGER)
	@JoinTable(name = DataBaseConstants.TABLE_GAMER_FRIENDS, joinColumns = @JoinColumn(name = DataBaseConstants.COLUMN_GAMER_ID, referencedColumnName = DataBaseConstants.COLUMN_ID), inverseJoinColumns = @JoinColumn(name = DataBaseConstants.COLUMN_FRIEND_ID, referencedColumnName = DataBaseConstants.COLUMN_ID))
	public List<Gamer> getFriends() {
		return friends;
	}

	public void setFriends(List<Gamer> friends) {
		this.friends = friends;
	}

	public void addFriend(Gamer newFriend) {
		if (friends == null) {
			friends = new ArrayList<Gamer>();
		}
		if (newFriend != null) {
			friends.add(newFriend);
		}
	}

	public void removeFriend(Gamer oldFriend) {
		if (friends != null && oldFriend != null) {
			friends.remove(oldFriend);
		}
	}

	@OneToMany(fetch = FetchType.EAGER)
	@JoinTable(name = DataBaseConstants.TABLE_PLAYER_GAMES, joinColumns = @JoinColumn(name = DataBaseConstants.COLUMN_PLAYER_ID, referencedColumnName = DataBaseConstants.COLUMN_ID), inverseJoinColumns = @JoinColumn(name = DataBaseConstants.COLUMN_GAME_ID, referencedColumnName = DataBaseConstants.COLUMN_ID))
	public List<Game> getGames() {
		return games;
	}

	public void setGames(List<Game> games) {
		this.games = games;
	}

	public void addGame(Game newGame) {
		if (games == null) {
			games = new ArrayList<Game>();
		}
		games.add(newGame);
	}

	public void removeGame(Game oldGame) {
		if (games != null) {
			games.remove(oldGame);
		}
	}

	public Game getGame(String name) {
		Game requestedGame = null;
		if (games != null && name != null && !name.isEmpty()) {
			for (Game game : games) {
				if (game.getName().equalsIgnoreCase(name)) {
					return game;
				}
			}
		}
		return requestedGame;
	}

	@OneToMany(mappedBy = "gamer", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
	public List<Authentication> getAuthentications() {
		return authentications;
	}

	public void setAuthentications(List<Authentication> authentications) {
		this.authentications = authentications;
	}

	public void addAuthentication(Authentication newAuth) {
		if (authentications == null) {
			authentications = new ArrayList<Authentication>();
		}
		authentications.add(newAuth);
	}

	public void removeAuthentication(Authentication oldAuth) {
		if (authentications != null) {
			authentications.remove(oldAuth);
		}
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((email == null) ? 0 : email.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Gamer other = (Gamer) obj;
		if (email == null) {
			if (other.email != null)
				return false;
		} else if (!email.equals(other.email))
			return false;
		return true;
	}

}
